﻿//
// Copyright (c) 2024 BPer
//

#include <bperutil/sys/BPerLibHandle.h>
#include <bperutil/sys/BPerLog.h>
#include <bperutil/sys/BPerFile.h>


#if BPer_OS_WIN
#include <windows.h>
#include <basetyps.h>
#ifdef _MSC_VER
#include <direct.h>
#endif
#else
   #include <dlfcn.h>
#endif




#if BPer_OS_WIN
#include <minwindef.h>
#define BPerModule HMODULE

#else
#define BPerModule void*
#endif

#if BPer_OS_WIN
char *bPer_libhandle_dlerror(){
    return (char*)"loadlib error";
}
#else
#define bPer_libhandle_dlerror dlerror
#endif


typedef struct{
	BPerModule handle;
}BPerLibContext;

void* bPer_libhandle_loadSysObject(void* pcontext,const char *sofile)
{
 if(pcontext==NULL) return NULL;
 BPerLibContext* context=(BPerLibContext*)pcontext;
#if BPer_OS_WIN
   // LPCSTR
 context->handle = LoadLibraryA(sofile);
#else
    context->handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL);
#endif

    if (context->handle == 0) {
          	bPer_error("Failed loading %s: %s", sofile,  bPer_libhandle_dlerror());
    }
    return (context->handle);
}
#define LENTH 200
void* bPer_libhandle_loadObject(void* pcontext,const char *sofile)
{
	 if(pcontext==NULL) return NULL;
	 BPerLibContext* context=(BPerLibContext*)pcontext;
	char file1[LENTH+50];
	char file_path_getcwd[LENTH];
	bPer_memset(file1, 0, LENTH+50);
	bPer_memset(file_path_getcwd, 0, LENTH);
    if(bPer_getLibpath(file_path_getcwd)!=BPer_Ok){
		bPer_error( "Failed loading shared obj %s: %s,getcwd error!", sofile, bPer_libhandle_dlerror());
		return NULL;
	}

#if BPer_OS_WIN
	bPer_sprintf(file1,sizeof(file1), "%s/%s.dll", file_path_getcwd, sofile);
	context->handle =  LoadLibraryA(file1);
#else
    bPer_sprintf(file1,sizeof(file1), "%s/%s.so", file_path_getcwd, sofile);
    context->handle = dlopen(file1, RTLD_NOW|RTLD_LOCAL);
#endif

    if (context->handle == 0) {

    	bPer_error( "Failed loading shared obj %s: %s", sofile, bPer_libhandle_dlerror());
    }
    return (context->handle);
}


void* bPer_libhandle_loadFunction(void* pcontext,const char *name)
{
	 if(pcontext==NULL) return NULL;
	 BPerLibContext* context=(BPerLibContext*)pcontext;
#if BPer_OS_WIN
	void *symbol = (void *) GetProcAddress(context->handle, name);
#else
	void *symbol = dlsym(context->handle, name);
#endif

    if (symbol == NULL) {
        	bPer_error("Failed loading function %s: %s", name, bPer_libhandle_dlerror());
    }
    return (symbol);
}

void bPer_libhandle_unloadObject(void* pcontext)
{
	 if(pcontext==NULL) return;
	 BPerLibContext* context=(BPerLibContext*)pcontext;
    if (context->handle) {
#if BPer_OS_WIN
    	 FreeLibrary( context->handle);
#else
	 dlclose(context->handle);;
#endif
	 context->handle=NULL;

    }
}

void bPer_create_libhandle(BPerLibHandle* handle){
	if(handle==NULL) return;
	handle->context=bPer_calloc(sizeof(BPerLibContext),1);
	handle->getError=bPer_libhandle_dlerror;
	handle->loadFunction=bPer_libhandle_loadFunction;
	handle->loadObject=bPer_libhandle_loadObject;
	handle->loadSysObject=bPer_libhandle_loadSysObject;
	handle->unloadObject=bPer_libhandle_unloadObject;
}
void bPer_destroy_libhandle(BPerLibHandle* handle){
	if(handle==NULL) return;
	handle->unloadObject(handle->context);
	bPer_free(handle->context);
}
